<template>
  <div class="LineDraggable">
    <div class="inputBox">
      <input
        id="deleteCanvas"
        type="button"
        value="清空坐标"
        @click="ClickClear"
      />
      <input id="putCanvas" type="button" value="提交坐标" @click="ClickPut" />
      <input
        id="drawCanvas"
        type="button"
        value="绘制坐标"
        @click="ClickDraw"
      />
      <input
        id="resetCanvas"
        type="button"
        value="重置坐标"
        @click="ClickReset"
      />
      <input id="setCanvas" type="button" value="生成坐标" @click="ClickSet" />
    </div>
    <div class="canvasBox">
      <img ref="img" class="img" src="../assets/OIP2.jpg" alt />
      <!--用来和鼠标进行交互操作的canvas-->
      <canvas
        id="canvas"
        :class="isReset ? 'borderRed' : ''"
        @mousemove="MouseMove"
        @mousedown="clickPoint"
        @mouseup="stopDragging"
        width="1000"
        height="600"
      ></canvas>
      <!--存储已生成的点线，避免被清空-->
      <canvas id="canvasSave" width="1000" height="600"></canvas>
    </div>
  </div>
</template>
<script>
export default {
  data() {
    return {
      can: null,
      ctx: null,
      canSave: null,
      ctxSave: null,
      pointX: null,
      pointY: null,
      drawEnd: true, // 结束绘制
      isReset: false, // 是否重置
      pointArr: [], //存放坐标的数组
      pointArrSave: [], //保存存放坐标的数组
      oIndex: -1, //判断鼠标是否移动到起始点处，-1为否，1为是
      ctxFillStyle: "rgba(161,195,255,0)", // 填充颜色
      ctxSaveFillStyle: "rgba(161,195,255,0)", // 填充颜色
      arcFillStyle: "rgba(178,34,34,1)", // 圆点的填充颜色
      selectObject: null, // 选择的拖动点在pointArrSave的位置
      isDragging: false, // 是否可以拖动
    };
  },
  mounted() {
    this.can = document.getElementById("canvas");
    this.ctx = this.can.getContext("2d");
    this.canSave = document.getElementById("canvasSave");
    this.ctxSave = this.canSave.getContext("2d");
    this.ctx.strokeStyle = "rgba(178,34,34,1)"; //线条颜色
    this.ctx.lineWidth = 2; //线条粗细
    this.ctxSave.strokeStyle = "rgba(178,34,34,1)"; //线条颜色
    this.ctxSave.lineWidth = 2; //线条粗细
  },
  methods: {
    // 停止拖动事件
    stopDragging(e) {
      if (this.isDragging) {
        this.isDragging = false;
      } else {
        this.ClickDrawPoint(e);
      }
    },
    // 拖动重新画图
    dragCircle(e) {
      // 判断是否可以拖动
      if (this.isDragging == true) {
        // 取得画布上被点击的点
        this.pointArrSave[this.selectObject[0]][this.selectObject[1]][0] =
          e.offsetX;
        this.pointArrSave[this.selectObject[0]][this.selectObject[1]][1] =
          e.offsetY;
        this.drawRects(this.pointArrSave);
      }
    },
    // 重新画图
    drawRects(data) {
      if (data) {
        this.isReset = false;
        this.ClickClear();
        data.forEach((item, index) => {
          item.forEach((item1, index1) => {
            this.pointArr.push({ x: item1[0], y: item1[1] });
          });
          this.canvasSave(this.pointArr); //保存点线同步到另一个canvas
          this.saveCanvas(); //生成画布
        });
      }
    },
    // 遍历元素在哪一个圆上
    circle(e, Array, clientX, clientY, index) {
      for (let i = 0; i < Array.length; i++) {
        const ele = Array[i];
        // Math.abs返回绝对值
        // Math.sqrt返回一个数的平方根
        // Math.pow幂函数运算
        var line = Math.abs(
          Math.sqrt(
            Math.pow(ele[0] - clientX, 2) + Math.pow(ele[1] - clientY, 2)
          )
        );
        // 判断点击的位置在哪一个圆里面
        if (line - 5 < 0) {
          this.isDragging = true;
          this.selectObject = [index, i];
        }
      }
    },
    // Canvas点击事件
    // 遍历所有的坐标点
    clickPoint(e) {
      if (this.pointArrSave.length > 0) {
        this.pointArrSave.forEach((item, index) => {
          this.circle(e, item, e.offsetX, e.offsetY, index);
        });
      }
    },
    // 绘制坐标
    ClickDraw() {
      this.drawEnd = false;
      this.isReset = false;
    },
    // 生成坐标
    ClickSet() {
      this.isReset = false;
      this.ClickClear();
      let dataTest =
        "[[[25,44],[213,156]],[[110,26],[37,99]],[[204,110],[206,31]],[[166,33],[80,159]],[[25,136],[186,82]]]";
      JSON.parse(dataTest).forEach((item, index) => {
        item.forEach((item1, index1) => {
          this.pointArr.push({
            x: item1[0] / this.getZoomRatio().scaleX,
            y: item1[1] / this.getZoomRatio().scaleY,
          });
        });
        console.info("生成坐标", this.pointArr);
        this.canvasSave(this.pointArr); //保存点线同步到另一个canvas
        this.saveCanvas(); //生成画布
      });
    },
    // 重置坐标
    ClickReset() {
      this.isReset = true;
      this.ClickClear();
    },
    // 提交坐标
    ClickPut() {
      let data = null;
      this.pointArrSave.forEach((item, index) => {
        item.forEach((item1, index1) => {
          item1[0] = parseInt(item1[0] * this.getZoomRatio().scaleX);
          item1[1] = parseInt(item1[1] * this.getZoomRatio().scaleY);
        });
      });
      data = JSON.stringify(this.pointArrSave);
      console.info("提交坐标", data);
    },
    // 点击画点
    ClickDrawPoint(e) {
      if (!this.drawEnd && !this.isDragging) {
        if (e.offsetX || e.layerX) {
          this.pointX = e.offsetX == undefined ? e.layerX : e.offsetX;
          this.pointY = e.offsetY == undefined ? e.layerY : e.offsetY;
          let piX, piY;
          piX = this.pointX;
          piY = this.pointY;
          this.makearc(
            this.ctx,
            piX,
            piY,
            this.GetRandomNum(2, 2),
            0,
            180,
            this.arcFillStyle
          );
          this.pointArr.push({ x: piX, y: piY });
          this.canvasSave(this.pointArr); //保存点线同步到另一个canvas
          if (this.pointArr.length === 2) {
            this.saveCanvas(); //生成画布
          }
        }
      }
    },
    // 鼠标移动
    MouseMove(e) {
      this.dragCircle(e);
      if (e.offsetX || e.layerX) {
        this.pointX = e.offsetX == undefined ? e.layerX : e.offsetX;
        this.pointY = e.offsetY == undefined ? e.layerY : e.offsetY;
        let piX, piY;
        /*清空画布*/
        this.ctx.clearRect(0, 0, this.can.width, this.can.height);
        /*鼠标下跟随的圆点*/
        this.makearc(
          this.ctx,
          this.pointX,
          this.pointY,
          this.GetRandomNum(4, 4),
          0,
          180,
          this.arcFillStyle
        );

        if (this.pointArr.length > 0) {
          if (
            this.pointX > this.pointArr[0].x - 15 &&
            this.pointX < this.pointArr[0].x + 15 &&
            this.pointY > this.pointArr[0].y - 15 &&
            this.pointY < this.pointArr[0].y + 15
          ) {
            if (this.pointArr.length > 1) {
              piX = this.pointArr[0].x;
              piY = this.pointArr[0].y;
              this.ctx.clearRect(0, 0, this.can.width, this.can.height);
              this.makearc(
                this.ctx,
                piX,
                piY,
                this.GetRandomNum(4, 4),
                0,
                180,
                this.arcFillStyle
              );
              this.oIndex = 1;
            }
          } else {
            piX = this.pointX;
            piY = this.pointY;
            this.oIndex = -1;
          }
          /*开始绘制*/
          this.ctx.beginPath();
          this.ctx.moveTo(this.pointArr[0].x, this.pointArr[0].y);
          if (this.pointArr.length > 1) {
            for (var i = 1; i < this.pointArr.length; i++) {
              this.ctx.lineTo(this.pointArr[i].x, this.pointArr[i].y);
            }
          }
          this.ctx.lineTo(piX, piY);
          this.ctx.fillStyle = this.ctxFillStyle; //填充颜色
          this.ctx.fill(); //填充
          this.ctx.stroke(); //绘制
        }
      }
    },
    // 存储已生成的点线
    canvasSave(pointArr) {
      this.ctxSave.clearRect(0, 0, this.ctxSave.width, this.ctxSave.height);
      // 每个节点生成圆点
      for (let i = 0; i < pointArr.length; i++) {
        this.makearc(
          this.ctxSave,
          pointArr[i].x,
          pointArr[i].y,
          this.GetRandomNum(4, 4),
          0,
          180,
          this.arcFillStyle
        );
      }
      this.ctxSave.beginPath();
      if (pointArr.length > 1) {
        this.ctxSave.moveTo(pointArr[0].x, pointArr[0].y);
        for (let i = 1; i < pointArr.length; i++) {
          this.ctxSave.lineTo(pointArr[i].x, pointArr[i].y);
          this.ctxSave.fillStyle = this.ctxSaveFillStyle; //填充颜色
          this.ctxSave.fill();
          this.ctxSave.stroke(); //绘制
        }
      }
    },
    /*生成画布 结束绘画*/
    saveCanvas() {
      let pointArrSaveTemp = [];
      this.ctx.clearRect(0, 0, this.can.width, this.can.height);
      this.drawEnd = true;
      this.ctxSave.fill(); //填充
      this.ctxSave.stroke(); //绘制
      this.pointArr.forEach((item, index) => {
        pointArrSaveTemp.push([item.x, item.y]);
      });
      this.pointArrSave.push(pointArrSaveTemp);
      this.pointArr = [];
      // 限制只能画五个区域
      if (this.pointArrSave.length < 5) {
        this.ClickDraw();
      }
    },
    /*清空选区*/
    ClickClear() {
      this.ctx.clearRect(0, 0, this.can.width, this.can.height);
      this.ctxSave.clearRect(0, 0, this.canSave.width, this.canSave.height);
      this.pointArr = [];
      this.pointArrSave = [];
      this.drawEnd = true;
    },
    /*验证canvas画布是否为空函数*/
    isCanvasBlank(canvas) {
      let blank = document.createElement("canvas"); //创建一个空canvas对象
      blank.width = canvas.width;
      blank.height = canvas.height;
      return canvas.toDataURL() == blank.toDataURL(); //为空 返回true
    },
    /*canvas生成圆点*/
    GetRandomNum(Min, Max) {
      let Range = Max - Min;
      let Rand = Math.random();
      return Min + Math.round(Rand * Range);
    },
    makearc(ctx, x, y, r, s, e, color) {
      // ctx.clearRect(0, 0, this.can.width, this.can.height); //清空画布 为了每个节点生成圆点，注释掉，不生成圆点需要取消注释
      ctx.beginPath();
      ctx.fillStyle = color;
      ctx.arc(x, y, r, s, e);
      ctx.fill();
    },
    // 获取缩放比例
    getZoomRatio() {
      let img = this.$refs.img;
      let naturalWidth = parseInt(img.naturalWidth);
      let naturalHeight = parseInt(img.naturalHeight);
      let width = parseInt(img.width);
      let height = parseInt(img.height);
      return {
        scaleX: naturalWidth / width,
        scaleY: naturalHeight / height,
      };
    },
  },
};
</script>
<style lang="scss" scoped>
.LineDraggable {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  .inputBox {
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 20px 0;
    input {
      width: 100px;
      font-size: 16px;
      margin: 0 5px;
    }
  }
  .canvasBox {
    width: 1000px;
    height: 600px;
    position: relative;
    canvas {
      // border: 2px solid transparent;
      display: block;
      width: 1000px;
      height: 600px;
    }
    .borderRed {
      // border: 2px solid #ff3d3d;
      box-shadow: 0 0 0 2px #ff3d3d inset;
    }
    #canvas {
      position: absolute;
      z-index: 1;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      cursor: crosshair;
    }

    #canvasSave {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
    .img {
      width: 100%;
      height: 100%;
    }
  }
}
</style>